using System;
using System.Collections.Generic;
using System.Linq;
using HCore.Core;
using HCore.Unity.Core;
using UnityEngine;
using Random = UnityEngine.Random;

namespace HCore.Tests.Runtime.Minesweeper.Scripts
{
    public class Map
    {
        private readonly Grid2D<MapGridObject> mGrid2D;

        public Map(int mineCount, int width, int height)
        {
            mGrid2D = new Grid2D<MapGridObject>(width, height, (g, x, y) => new MapGridObject(g, x, y));

            // 这里随机放一些Mine
            ForUtils.ForRepeat(mineCount, index =>
            {
                var x = Random.Range(0, mGrid2D.Width);
                var y = Random.Range(0, mGrid2D.Height);

                var mapGridObject = mGrid2D.GetCell(x, y);
                if (mapGridObject.GridType == GridType.Mine) return false;
                mapGridObject.GridType = GridType.Mine;
                return true;
            });

            // 遍历空格，计算周边的 Mine 数据
            ForUtils.For(mGrid2D.Width, mGrid2D.Height, (x, y) =>
            {
                var mapGridObject = mGrid2D.GetCell(x, y);
                if (mapGridObject.GridType == GridType.Empty)
                {
                    var neighbourList = GetNeighbourList(x, y);
                    var minCount = neighbourList.Count(gridObject => gridObject.GridType == GridType.Mine);
                    mapGridObject.GridType = minCount switch
                    {
                        1 => GridType.MineNum1,
                        2 => GridType.MineNum2,
                        3 => GridType.MineNum3,
                        4 => GridType.MineNum4,
                        5 => GridType.MineNum5,
                        6 => GridType.MineNum6,
                        7 => GridType.MineNum7,
                        8 => GridType.MineNum8,
                        _ => mapGridObject.GridType
                    };
                }
            });
        }

        public event Action OnEntireMapRevealed;

        private List<MapGridObject> GetNeighbourList(MapGridObject gridObject)
        {
            return GetNeighbourList(gridObject.X, gridObject.Y);
        }

        private List<MapGridObject> GetNeighbourList(int x, int y)
        {
            var neighbourList = new List<MapGridObject>(8);
            ForUtils.ForNeighbour(x, y, (a, b) =>
            {
                if (a < 0 || b < 0 || a >= mGrid2D.Width || b >= mGrid2D.Height) return;
                neighbourList.Add(mGrid2D.GetCell(a, b));
            });
            return neighbourList;
        }

        public Grid2D<MapGridObject> GetGrid()
        {
            return mGrid2D;
        }

        // 翻格子
        public GridType? RevealGridPosition(Vector2 worldPosition)
        {
            var mapGridObject = mGrid2D.GetCell(worldPosition);
            return mapGridObject != default ? RevealGrid(mapGridObject) : null;
        }

        // 翻格子
        public GridType? RevealGrid(MapGridObject gridObject)
        {
            GridType? GridObjectGridType(MapGridObject mapGridObject)
            {
                // 已经翻开的跳过
                if (mapGridObject.Revealed) return mapGridObject.GridType;

                // 翻开格子
                mapGridObject.Reveal();

                // 当前格子不是空格子，则跳过
                if (mapGridObject.GridType != GridType.Empty) return mapGridObject.GridType;

                // 如果当前格子是空格子，则翻开四周连续的空格子
                var neighbourList = GetNeighbourList(mapGridObject);
                foreach (var neighbourGridObject in neighbourList.Where(neighbourGridObject =>
                             neighbourGridObject.GridType != GridType.Mine && !neighbourGridObject.Revealed))
                    GridObjectGridType(neighbourGridObject);


                return mapGridObject.GridType;
            }

            if (gridObject == null) return null;

            var gridType = GridObjectGridType(gridObject);

            // 判断是否赢得了游戏
            var entireMapRevealed = IsEntireMapRevealed();
            if (entireMapRevealed) OnEntireMapRevealed?.Invoke();

            return gridType;
        }

        /// <summary>
        ///     格子是否已经全部翻开
        /// </summary>
        /// <returns></returns>
        private bool IsEntireMapRevealed()
        {
            var revealed = true;
            ForUtils.For(mGrid2D.Width, mGrid2D.Height, (x, y) =>
            {
                var gridObject = mGrid2D.GetCell(x, y);
                revealed = gridObject.GridType == GridType.Mine || gridObject.Revealed;
                return revealed;
            });
            return revealed;
        }
    }
}